package org.java.vm.command;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ArithmeticHandler {

    private String variablePrefix;


    public List<String> pushDToStack() {
        return Arrays.asList("@SP", "A=M", "M=D", "@SP", "M=M+1");
    }

    /**
     * pop后将栈数据保存到 D寄存器
     *
     * @return
     */
    public List<String> pop() {
        return Arrays.asList("@SP", "M=M-1");
    }

    public List<String> operateTwoDigit(List<String> addedCommands) {
        List<String> commands = new ArrayList<>();
        // 取栈上两个数值，并将结果保存到M[sp-2]中
        commands.addAll(pop());
        commands.add("@SP");
        commands.add("A=M");
        commands.add("D=M");

        commands.addAll(pop());
        commands.add("@SP");
        commands.add("A=M");
        // A寄存器已经指定到sp-2位置
        // commands.add("M=M-D");
        commands.addAll(addedCommands);

        commands.addAll(pushDToStack());
        return commands;
    }

    public List<String> operateOneDigit(List<String> addedCommands) {
        List<String> commands = new ArrayList<>();
        // 取栈上两个数值，并将结果保存到M[sp-2]中
        commands.add("@SP");
        commands.add("A=M-1");
        commands.addAll(addedCommands);

        return commands;
    }

    public List<String> pop(String arg1, int arg2) {
        List<String> commands = new ArrayList<>();
        commands.addAll(pop());
        Segment segment = Segment.resultOf(arg1);
        if (arg1.equalsIgnoreCase("static")) {
            // 栈上数据存入D寄存器
            commands.add("@SP");
            commands.add("A=M");
            commands.add("D=M");

            commands.add("@" + variablePrefix + arg2);
            commands.add("M=D");
            return commands;
        }
        // R13记录 偏移量
        commands.add("@" + arg2);
        commands.add("D=A");
        commands.add("@" + segment.asmSymbol);
        if (segment.isBaseRegister) {
            commands.add("D=D+M");
        } else {
            commands.add("D=D+A");
        }
        commands.add("@R13");
        commands.add("M=D");

        // 栈上数据存入D寄存器
        commands.add("@SP");
        commands.add("A=M");
        commands.add("D=M");

        // R13指定的地址保存D寄存器中的值
        commands.add("@R13");
        commands.add("A=M");
        commands.add("M=D");
        return commands;
    }

    public void setVariablePrefix(String variablePrefix) {
        this.variablePrefix = variablePrefix;
    }

    private enum Segment {
        LOCAL("LCL", true),
        POINTER("R3", false),
        THIS("THIS", true),

        THAT("THAT", true),
        ARGUMENT("ARG", true),
        TEMP("R5", false);

        private String asmSymbol;
        private boolean isBaseRegister;

        Segment(String asmSymbol, boolean isBaseRegister) {
            this.asmSymbol = asmSymbol;
            this.isBaseRegister = isBaseRegister;
        }

        public static Segment resultOf(String command) {
            for (Segment segment : values()) {
                if (segment.name().equalsIgnoreCase(command)) {
                    return segment;
                }
            }
            return null;
        }

    }

}
